#include "shader.h"
#include "shader.h"
#include "../wrapper/checkErr.h"
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>


Shader::Shader(const char* vertexPath, const char* fragementPath) {
	std::string vertexShaderCode;
	std::string fragementShaderCode;
	std::ifstream vertexShaderIn;
	std::ifstream fragementShaderIn;
	vertexShaderIn.exceptions(std::ifstream::failbit | std::ifstream::badbit);
	fragementShaderIn.exceptions(std::ifstream::failbit | std::ifstream::badbit);
	try
	{
		vertexShaderIn.open(vertexPath);
		fragementShaderIn.open(fragementPath);

		std::stringstream vShaderStream, fShaderStream;
		vShaderStream << vertexShaderIn.rdbuf();
		fShaderStream << fragementShaderIn.rdbuf();

		vertexShaderIn.close();
		fragementShaderIn.close();

		vertexShaderCode = vShaderStream.str();
		fragementShaderCode = fShaderStream.str();

	}
	catch (const std::ifstream::failure& e)
	{
		std::cout << "ERROR READ SHADER fail:" << e.what() << std::endl;
	}

	const char* vertexShaderSource = vertexShaderCode.c_str();
	const char* fragmentShaderSource = fragementShaderCode.c_str();

	//2.创建shader程序（vs，fs）
	GLuint vertex, fragment;
	vertex = glCreateShader(GL_VERTEX_SHADER);
	fragment = glCreateShader(GL_FRAGMENT_SHADER);

	//3.为shader程序输入shader代码
	glShaderSource(vertex, 1, &vertexShaderSource, NULL);
	glShaderSource(fragment, 1, &fragmentShaderSource, NULL);

	int success = 0;
	char infoLog[1024];
	//4.执行shader代码编译
	glCompileShader(vertex);
	this->checkShaderErrors(vertex,COMPILE);
	
	glCompileShader(fragment);
	this->checkShaderErrors(fragment, COMPILE);
	

	//5.创建一个program的壳子
	this->program = glCreateProgram();

	//6.将vs和fs编译好的结果放到program这个壳子中
	glAttachShader(this->program, vertex);
	glAttachShader(this->program, fragment);

	//7.执行program的链接操作，形成最终可执行的shader程序
	glLinkProgram(this->program);
	this->checkShaderErrors(this->program, LINK);

	//8.清理
	glDeleteShader(vertex);
	glDeleteShader(fragment);
}

Shader::~Shader() {

}
GLuint Shader::getProgram() {
	return this->program;
}
void Shader::begin() {
	GL_CALL(glUseProgram(this->program), "glUseProgram begin err:");
}
void Shader::end() {
	GL_CALL(glUseProgram(0), "glUseProgram end err:");
}
void Shader::setFloat(const std::string& name, float value)
{
	//1.通过名称拿到Unifor变量的Location
	GLint location = GL_CALL(glGetUniformLocation(this->program,name.c_str()),".通过名称拿到Unifor变量的Location");
	//2.通过Localtion更新变量的值
	GL_CALL(glUniform1f(location, value),"通过Localtion更新变量的值");
}
void Shader::setVector3(const std::string& name, float x, float y, float z) {
	//1.通过名称拿到Unifor变量的Location
	GLint location = GL_CALL(glGetUniformLocation(this->program, name.c_str()), ".通过名称拿到Unifor变量的Location");
	//2.通过Localtion更新变量的值
	GL_CALL(glUniform3f(location, x,y,z), "通过Localtion更新变量的值");
}

void Shader::setVector3(const std::string& name, const float* values) {
	//1.通过名称拿到Unifor变量的Location
	GLint location = GL_CALL(glGetUniformLocation(this->program, name.c_str()), ".通过名称拿到Unifor变量的Location");
	//2.通过Localtion更新变量的值
	//第二个参数表示当前要更新的unifor变量如果是数组，数组里包括多少个vec3
	GL_CALL(glUniform3fv(location, 1,values), "通过Localtion更新变量的值");
}
void Shader::checkShaderErrors(GLuint target, ShaderType type) {
	int success = 0;
	char infoLog[1024];
	switch (type)
	{
	case COMPILE:
		//获取编译结果
		glGetShaderiv(target, GL_COMPILE_STATUS, &success);
		if (!success) {
			glGetShaderInfoLog(target, 1024, NULL, infoLog);
			std::cout << "vertex shader compile err : " << infoLog << std::endl;
		}
		break;
	case LINK:
		//检查链接错误
		glGetProgramiv(target, GL_LINK_STATUS, &success);
		if (!success) {
			glGetProgramInfoLog(this->program, 1024, NULL, infoLog);
			std::cout << "program link err : " << infoLog << std::endl;
		}
		break;
	default:
		std::cout << "ERROR: Check shader errors type is wrong" << std::endl;
		break;
	}
}